import element.base.Synt;
import element.base.Word;
import element.base.Wordtype;
import element.synt.*;
import element.synt.Number;

import java.util.ArrayList;

public class Syntax {
    private ArrayList<Word> words;
    private int pointer;
    private Word nowWord;

    public Syntax(ArrayList<Word> words) {
        this.words = words;
        this.pointer = 0;
        this.nowWord = null;
    }

    public void getSym() {
        if (pointer < words.size()) {
            nowWord = words.get(pointer++);
        }
        return;
    }

    public void rollback(int n) {
        for (int i = 0; i < n; i++) {
            pointer--;
        }
        nowWord = words.get(pointer - 1);
    }

    public Synt Execute() {
        getSym();
        return CompUnit();
    }

    //CompUnit → {Decl} {FuncDef} MainFuncDef
    public Synt CompUnit() {
        Synt compunit = new CompUnit();
        while (true) {
            if (nowWord.getType().equals(Wordtype.CONSTTK)) {
                Synt decl = Decl();
                compunit.addNode(decl);
            } else if (nowWord.getType().equals(Wordtype.INTTK)) {
                if (words.get(pointer + 1).getType().equals(Wordtype.LPARENT)) {
                    break;
                } else {
                    Synt decl = Decl();
                    compunit.addNode(decl);
                }
            } else {
                break;
            }
        }
        while (true) {
            if (nowWord.getType().equals(Wordtype.VOIDTK)) {
                Synt funcdef = FuncDef();
                compunit.addNode(funcdef);
            } else if (nowWord.getType().equals(Wordtype.INTTK)) {
                if (words.get(pointer).getType().equals(Wordtype.MAINTK)) {
                    break;
                } else {
                    Synt funcdef = FuncDef();
                    compunit.addNode(funcdef);
                }
            } else {
                error();
            }
        }
        Synt mainfuncdef = MainFuncDef();
        compunit.addNode(mainfuncdef);
        return compunit;
    }

    //Decl → ConstDecl | VarDecl
    public Synt Decl() {
        Synt decl = new Decl();
        if (nowWord.getType().equals(Wordtype.CONSTTK)) {
            Synt constdecl = ConstDecl();
            decl.addNode(constdecl);
        } else if (nowWord.getType().equals(Wordtype.INTTK)) {
            Synt vardecl = VarDecl();
            decl.addNode(vardecl);
        } else {
            error();
        }
        return decl;
    }

    //ConstDecl → 'const' BType ConstDef { ',' ConstDef } ';'
    public Synt ConstDecl() {
        Synt constdecl = new ConstDecl();
        if (!nowWord.getType().equals(Wordtype.CONSTTK)) {
            error();
        } else {
            constdecl.addNode(nowWord);
            getSym();
            if (!nowWord.getType().equals(Wordtype.INTTK)) {
                error();
            } else {
                Synt btype = Btype();
                constdecl.addNode(btype);
                if (!nowWord.getType().equals(Wordtype.IDENFR)) {
                    error();
                } else {
                    Synt constdef = ConstDef();
                    constdecl.addNode(constdef);
                    while (nowWord.getType().equals(Wordtype.COMMA)) {
                        constdecl.addNode(nowWord);
                        getSym();
                        if (!nowWord.getType().equals(Wordtype.IDENFR)) {
                            error();
                        } else {
                            Synt constdef1 = ConstDef();
                            constdecl.addNode(constdef1);
                        }
                    }
                    if (nowWord.getType().equals(Wordtype.SEMICN)) {
                        constdecl.addNode(nowWord);
                        getSym();
                    }
                }
            }
        }
        return constdecl;
    }

    //BType → 'int'
    public Synt Btype() {
        Synt btype = new BType();
        if (nowWord.getType().equals(Wordtype.INTTK)) {
            btype.addNode(nowWord);
        } else {
            error();
        }
        getSym();
        return btype;
    }

    //ConstDef → Ident { '[' ConstExp ']' } '=' ConstInitVal
    public Synt ConstDef() {
        Synt constdef = new ConstDef();
        if (nowWord.getType().equals(Wordtype.IDENFR)) {
            constdef.addNode(nowWord);
            getSym();
            while (nowWord.getType().equals(Wordtype.LBRACK)) {
                constdef.addNode(nowWord);
                getSym();
                Synt constexp = ConstExp();
                constdef.addNode(constexp);
                if (nowWord.getType().equals(Wordtype.RBRACK)) {
                    constdef.addNode(nowWord);
                    getSym();
                }
            }
            if (nowWord.getType().equals(Wordtype.ASSIGN)) {
                constdef.addNode(nowWord);
                getSym();
                Synt constinitval = ConstInitVal();
                constdef.addNode(constinitval);
            } else {
                error();
            }
        } else {
            error();
        }
        return constdef;
    }

    //ConstInitVal → ConstExp | '{' [ ConstInitVal { ',' ConstInitVal } ] '}'
    public Synt ConstInitVal() {
        Synt constinitval = new ConstInitVal();
        if (nowWord.getType().equals(Wordtype.LBRACE)) {
            constinitval.addNode(nowWord);
            getSym();
            if (!nowWord.getType().equals(Wordtype.RBRACE)) {
                Synt constinitval1 = ConstInitVal();
                constinitval.addNode(constinitval1);
                while (nowWord.getType().equals(Wordtype.COMMA)) {
                    constinitval.addNode(nowWord);
                    getSym();
                    Synt constinitval2 = ConstInitVal();
                    constinitval.addNode(constinitval2);
                }
            }
            if (nowWord.getType().equals(Wordtype.RBRACE)) {
                constinitval.addNode(nowWord);
            } else {
                error();
            }
            getSym();
        } else {
            Synt constexp = ConstExp();
            constinitval.addNode(constexp);
        }
        return constinitval;
    }

    //VarDecl → BType VarDef { ',' VarDef } ';'
    public Synt VarDecl() {
        Synt vardecl = new VarDecl();
        Synt btype = Btype();
        vardecl.addNode(btype);
        Synt vardef = VarDef();
        vardecl.addNode(vardef);
        while (nowWord.getType().equals(Wordtype.COMMA)) {
            vardecl.addNode(nowWord);
            getSym();
            Synt vardef1 = VarDef();
            vardecl.addNode(vardef1);
        }
        if (nowWord.getType().equals(Wordtype.SEMICN)) {
            vardecl.addNode(nowWord);
            getSym();
        }
        return vardecl;
    }

    //VarDef → Ident { '[' ConstExp ']' } | Ident { '[' ConstExp ']' } '=' InitVal
    public Synt VarDef() {
        Synt vardef = new VarDef();
        if (nowWord.getType().equals(Wordtype.IDENFR)) {
            vardef.addNode(nowWord);
            getSym();
            while (nowWord.getType().equals(Wordtype.LBRACK)) {
                vardef.addNode(nowWord);
                getSym();
                Synt constexp = ConstExp();
                vardef.addNode(constexp);
                if (nowWord.getType().equals(Wordtype.RBRACK)) {
                    vardef.addNode(nowWord);
                    getSym();
                }
            }
            if (nowWord.getType().equals(Wordtype.ASSIGN)) {
                vardef.addNode(nowWord);
                getSym();
                Synt initval = InitVal();
                vardef.addNode(initval);
            }
        } else {
            error();
        }
        return vardef;
    }

    //InitVal → Exp | '{' [ InitVal { ',' InitVal } ] '}'
    public Synt InitVal() {
        Synt initval = new InitVal();
        if (nowWord.getType().equals(Wordtype.LBRACE)) {
            initval.addNode(nowWord);
            getSym();
            if (!nowWord.getType().equals(Wordtype.RBRACE)) {
                Synt initval1 = InitVal();
                initval.addNode(initval1);
                while (nowWord.getType().equals(Wordtype.COMMA)) {
                    initval.addNode(nowWord);
                    getSym();
                    Synt initval2 = InitVal();
                    initval.addNode(initval2);
                }
            }
            if (nowWord.getType().equals(Wordtype.RBRACE)) {
                initval.addNode(nowWord);
                getSym();
            } else {
                error();
            }
        } else {
            Synt exp = Exp();
            initval.addNode(exp);
        }
        return initval;
    }

    //FuncDef → FuncType Ident '(' [FuncFParams] ')' Block
    public Synt FuncDef() {
        Synt funcdef = new FuncDef();
        Synt functype = FuncType();
        funcdef.addNode(functype);
        if (nowWord.getType().equals(Wordtype.IDENFR)) {
            funcdef.addNode(nowWord);
            getSym();
            if (nowWord.getType().equals(Wordtype.LPARENT)) {
                funcdef.addNode(nowWord);
                getSym();
                if (!nowWord.getType().equals(Wordtype.RPARENT)) {
                    if (!nowWord.getType().equals(Wordtype.LBRACE)) {
                        Synt funcfparams = FuncFParams();
                        funcdef.addNode(funcfparams);
                    }
                }
                if (nowWord.getType().equals(Wordtype.RPARENT)) {
                    funcdef.addNode(nowWord);
                    getSym();
                }
            } else {
                error();
            }
        } else {
            error();
        }
        Synt block = Block();
        funcdef.addNode(block);
        return funcdef;
    }

    //MainFuncDef → 'int' 'main' '(' ')' Block
    public Synt MainFuncDef() {
        Synt mainfuncdef = new MainFuncDef();
        if (nowWord.getType().equals(Wordtype.INTTK)) {
            mainfuncdef.addNode(nowWord);
            getSym();
            if (nowWord.getType().equals(Wordtype.MAINTK)) {
                mainfuncdef.addNode(nowWord);
                getSym();
                if (nowWord.getType().equals(Wordtype.LPARENT)) {
                    mainfuncdef.addNode(nowWord);
                    getSym();
                    if (nowWord.getType().equals(Wordtype.RPARENT)) {
                        mainfuncdef.addNode(nowWord);
                        getSym();
                        Synt block = Block();
                        mainfuncdef.addNode(block);
                    }
                } else {
                    error();
                }
            } else {
                error();
            }
        } else {
            error();
        }
        return mainfuncdef;
    }

    //FuncType → 'void' | 'int'
    public Synt FuncType() {
        Synt functype = new FuncType();
        if (nowWord.getType().equals(Wordtype.INTTK)) {
            functype.addNode(nowWord);
        } else if (nowWord.getType().equals(Wordtype.VOIDTK)) {
            functype.addNode(nowWord);
        } else {
            error();
        }
        getSym();
        return functype;
    }

    //FuncFParams → FuncFParam { ',' FuncFParam }
    public Synt FuncFParams() {
        Synt funcfparams = new FuncFParams();
        Synt funcfparam = FuncFParam();
        funcfparams.addNode(funcfparam);
        while (nowWord.getType().equals(Wordtype.COMMA)) {
            funcfparams.addNode(nowWord);
            getSym();
            Synt funcfparam1 = FuncFParam();
            funcfparams.addNode(funcfparam1);
        }
        return funcfparams;
    }

    //FuncFParam → BType Ident ['[' ']' { '[' ConstExp ']' }]
    public Synt FuncFParam() {
        Synt funcfparam = new FuncFParam();
        Synt btype = Btype();
        funcfparam.addNode(btype);
        if (nowWord.getType().equals(Wordtype.IDENFR)) {
            funcfparam.addNode(nowWord);
            getSym();
            if (nowWord.getType().equals(Wordtype.LBRACK)) {
                funcfparam.addNode(nowWord);
                getSym();
                if (nowWord.getType().equals(Wordtype.RBRACK)) {
                    funcfparam.addNode(nowWord);
                    getSym();
                }
                while (nowWord.getType().equals(Wordtype.LBRACK)) {
                    funcfparam.addNode(nowWord);
                    getSym();
                    Synt constexp = ConstExp();
                    funcfparam.addNode(constexp);
                    if (nowWord.getType().equals(Wordtype.RBRACK)) {
                        funcfparam.addNode(nowWord);
                        getSym();
                    }
                }
            }
        } else {
            error();
        }
        return funcfparam;
    }

    //Block → '{' { BlockItem } '}'
    public Synt Block() {
        Synt block = new Block();
        if (nowWord.getType().equals(Wordtype.LBRACE)) {
            block.addNode(nowWord);
            getSym();
            while (!nowWord.getType().equals(Wordtype.RBRACE)) {
                Synt blockitem = BlockItem();
                block.addNode(blockitem);
            }
            if (nowWord.getType().equals(Wordtype.RBRACE)) {
                block.addNode(nowWord);
                getSym();
            } else {
                error();
            }
        } else {
            error();
        }
        return block;
    }

    //BlockItem → Decl | Stmt
    public Synt BlockItem() {
        Synt blockitem = new BlockItem();
        if (nowWord.getType().equals(Wordtype.CONSTTK)) {
            Synt decl = Decl();
            blockitem.addNode(decl);
        } else if (nowWord.getType().equals(Wordtype.INTTK)) {
            Synt decl = Decl();
            blockitem.addNode(decl);
        } else {
            Synt stmt = Stmt();
            blockitem.addNode(stmt);
        }
        return blockitem;
    }

    //Stmt → LVal '=' Exp ';'
    // | [Exp] ';'
    // | Block
    // | 'if' '(' Cond ')' Stmt [ 'else' Stmt ]
    // | 'while' '(' Cond ')' Stmt
    // | 'break' ';' | 'continue' ';'
    // | 'return' [Exp] ';'
    // | LVal '=' 'getint''('')'';'
    // | 'printf''('FormatString{,Exp}')'';'
    public Synt Stmt() {
        Synt stmt = new Stmt();
        if (nowWord.getType().equals(Wordtype.IFTK)) {
            stmt.addNode(nowWord);
            getSym();
            if (nowWord.getType().equals(Wordtype.LPARENT)) {
                stmt.addNode(nowWord);
                getSym();
                Synt cond = Cond();
                stmt.addNode(cond);
                if (nowWord.getType().equals(Wordtype.RPARENT)) {
                    stmt.addNode(nowWord);
                    getSym();
                }
                Synt stmt1 = Stmt();
                stmt.addNode(stmt1);
                if (nowWord.getType().equals(Wordtype.ELSETK)) {
                    stmt.addNode(nowWord);
                    getSym();
                    Synt stmt2 = Stmt();
                    stmt.addNode(stmt2);
                }
            } else {
                error();
            }
        } else if (nowWord.getType().equals(Wordtype.WHILETK)) {
            stmt.addNode(nowWord);
            getSym();
            if (nowWord.getType().equals(Wordtype.LPARENT)) {
                stmt.addNode(nowWord);
                getSym();
                Synt cond = Cond();
                stmt.addNode(cond);
                if (nowWord.getType().equals(Wordtype.RPARENT)) {
                    stmt.addNode(nowWord);
                    getSym();
                }
                Synt stmt1 = Stmt();
                stmt.addNode(stmt1);
            } else {
                error();
            }
        } else if (nowWord.getType().equals(Wordtype.BREAKTK)) {
            stmt.addNode(nowWord);
            getSym();
            if (nowWord.getType().equals(Wordtype.SEMICN)) {
                stmt.addNode(nowWord);
                getSym();
            }
        } else if (nowWord.getType().equals(Wordtype.CONTINUETK)) {
            stmt.addNode(nowWord);
            getSym();
            if (nowWord.getType().equals(Wordtype.SEMICN)) {
                stmt.addNode(nowWord);
                getSym();
            }
        } else if (nowWord.getType().equals(Wordtype.RETURNTK)) {
            stmt.addNode(nowWord);
            getSym();
            if (nowWord.getType().equals(Wordtype.LPARENT) || nowWord.getType().equals(Wordtype.IDENFR) || nowWord.getType().equals(Wordtype.INTCON) || nowWord.getType().equals(Wordtype.PLUS) || nowWord.getType().equals(Wordtype.MINU)) {
                Synt exp = Exp();
                stmt.addNode(exp);
            }
            if (nowWord.getType().equals(Wordtype.SEMICN)) {
                stmt.addNode(nowWord);
                getSym();
            }
        } else if (nowWord.getType().equals(Wordtype.PRINTFTK)) {
            stmt.addNode(nowWord);
            getSym();
            if (nowWord.getType().equals(Wordtype.LPARENT)) {
                stmt.addNode(nowWord);
                getSym();
                if (nowWord.getType().equals(Wordtype.STRCON)) {
                    stmt.addNode(nowWord);
                    getSym();
                    while (nowWord.getType().equals(Wordtype.COMMA)) {
                        stmt.addNode(nowWord);
                        getSym();
                        Synt exp = Exp();
                        stmt.addNode(exp);
                    }
                    if (nowWord.getType().equals(Wordtype.RPARENT)) {
                        stmt.addNode(nowWord);
                        getSym();
                    }
                    if (nowWord.getType().equals(Wordtype.SEMICN)) {
                        stmt.addNode(nowWord);
                        getSym();
                    }
                } else {
                    error();
                }
            } else {
                error();
            }
        } else if (nowWord.getType().equals(Wordtype.LBRACE)) {
            Synt block = Block();
            stmt.addNode(block);
        } else if (nowWord.getType().equals(Wordtype.SEMICN)) {
            stmt.addNode(nowWord);
            getSym();
        } else if (nowWord.getType().equals(Wordtype.INTCON) || nowWord.getType().equals(Wordtype.LPARENT) ||
                nowWord.getType().equals(Wordtype.PLUS) || nowWord.getType().equals(Wordtype.MINU)) {
            Synt exp = Exp();
            stmt.addNode(exp);
            if (nowWord.getType().equals(Wordtype.SEMICN)) {
                stmt.addNode(nowWord);
                getSym();
            }
        } else if (nowWord.getType().equals(Wordtype.IDENFR)) {
            if (words.get(pointer).getType().equals(Wordtype.LPARENT)) {
                Synt exp = Exp();
                stmt.addNode(exp);
                if (nowWord.getType().equals(Wordtype.SEMICN)) {
                    stmt.addNode(nowWord);
                    getSym();
                }
            } else {
                boolean signer = false;
                int safe = 0;
                for (int i = pointer;;i++) {
                    if (words.get(i).getType().equals(Wordtype.ASSIGN)) {
                        signer = true;
                        break;
                    } else if (words.get(i).getType().equals(Wordtype.LBRACK)) {
                        safe++;
                    } else if (words.get(i).getType().equals(Wordtype.RBRACK)) {
                        safe--;
                    } else if (words.get(i).getType().equals(Wordtype.SEMICN) || i == words.size() - 1) {
                        break;
                    } else {
                        if (safe == 0) {
                            break;
                        }
                    }
                }
                if (signer) {
                    Synt lval = LVal();
                    stmt.addNode(lval);
                    if (nowWord.getType().equals(Wordtype.ASSIGN)) {
                        stmt.addNode(nowWord);
                        getSym();
                        if (nowWord.getType().equals(Wordtype.GETINTTK)) {
                            stmt.addNode(nowWord);
                            getSym();
                            if (nowWord.getType().equals(Wordtype.LPARENT)) {
                                stmt.addNode(nowWord);
                                getSym();
                                if (nowWord.getType().equals(Wordtype.RPARENT)) {
                                    stmt.addNode(nowWord);
                                    getSym();
                                }
                                if (nowWord.getType().equals(Wordtype.SEMICN)) {
                                    stmt.addNode(nowWord);
                                    getSym();
                                }
                            } else {
                                error();
                            }
                        } else {
                            Synt exp = Exp();
                            stmt.addNode(exp);
                            if (nowWord.getType().equals(Wordtype.SEMICN)) {
                                stmt.addNode(nowWord);
                                getSym();
                            }
                        }
                    } else {
                        error();
                    }
                } else {
                    Synt exp = Exp();
                    stmt.addNode(exp);
                    if (nowWord.getType().equals(Wordtype.SEMICN)) {
                        stmt.addNode(nowWord);
                        getSym();
                    }
                }
            }
        } else {
            error();
        }
        return stmt;
    }

    //Exp → AddExp
    public Synt Exp() {
        Synt exp = new Exp();
        Synt addexp = AddExp();
        exp.addNode(addexp);
        return exp;
    }

    //Cond → LOrExp
    public Synt Cond() {
        Synt cond = new Cond();
        Synt lorexp = LOrExp();
        cond.addNode(lorexp);
        return cond;
    }

    //LVal → Ident {'[' Exp ']'}
    public Synt LVal() {
        Synt lval = new LVal();
        if (nowWord.getType().equals(Wordtype.IDENFR)) {
            lval.addNode(nowWord);
            getSym();
            while (nowWord.getType().equals(Wordtype.LBRACK)) {
                lval.addNode(nowWord);
                getSym();
                Synt exp = Exp();
                lval.addNode(exp);
                if (nowWord.getType().equals(Wordtype.RBRACK)) {
                    lval.addNode(nowWord);
                    getSym();
                }
            }
        } else {
            error();
        }
        return lval;
    }

    //PrimaryExp → '(' Exp ')' | LVal | Number
    public Synt PrimaryExp() {
        Synt primaryexp = new PrimaryExp();
        if (nowWord.getType().equals(Wordtype.LPARENT)) {
            primaryexp.addNode(nowWord);
            getSym();
            Synt exp = Exp();
            primaryexp.addNode(exp);
            if (nowWord.getType().equals(Wordtype.RPARENT)) {
                primaryexp.addNode(nowWord);
                getSym();
            }
        } else if (nowWord.getType().equals(Wordtype.INTCON)) {
            Synt number = Number();
            primaryexp.addNode(number);
        } else {
            Synt lval = LVal();
            primaryexp.addNode(lval);
        }
        return primaryexp;
    }

    //Number → IntConst
    public Synt Number() {
        Synt number = new Number();
        if (nowWord.getType().equals(Wordtype.INTCON)) {
            number.addNode(nowWord);
            getSym();
        } else {
            error();
        }
        return number;
    }

    //UnaryExp → PrimaryExp | Ident '(' [FuncRParams] ')' | UnaryOp UnaryExp
    public Synt UnaryExp() {
        Synt unaryexp = new UnaryExp();
        if (nowWord.getType().equals(Wordtype.PLUS) || nowWord.getType().equals(Wordtype.MINU) ||
                nowWord.getType().equals(Wordtype.NOT)) {
            Synt unaryop = UnaryOp();
            unaryexp.addNode(unaryop);
            Synt unaryexp1 = UnaryExp();
            unaryexp.addNode(unaryexp1);
        } else if (nowWord.getType().equals(Wordtype.IDENFR) &&
                words.get(pointer).getType().equals(Wordtype.LPARENT)) {
            unaryexp.addNode(nowWord);
            getSym();
            unaryexp.addNode(nowWord);
            getSym();
            if (nowWord.getType().equals(Wordtype.LPARENT) || nowWord.getType().equals(Wordtype.IDENFR) || nowWord.getType().equals(Wordtype.INTCON) || nowWord.getType().equals(Wordtype.PLUS) || nowWord.getType().equals(Wordtype.MINU)) {
                Synt funcrparams = FuncRParams();
                unaryexp.addNode(funcrparams);
            }
            if (nowWord.getType().equals(Wordtype.RPARENT)) {
                unaryexp.addNode(nowWord);
                getSym();
            }
        } else {
            Synt primaryexp = PrimaryExp();
            unaryexp.addNode(primaryexp);
        }
        return unaryexp;
    }

    //UnaryOp → '+' | '−' | '!'
    public Synt UnaryOp() {
        Synt unaryop = new UnaryOp();
        if (nowWord.getType().equals(Wordtype.PLUS)) {
            unaryop.addNode(nowWord);
        } else if (nowWord.getType().equals(Wordtype.MINU)) {
            unaryop.addNode(nowWord);
        } else if (nowWord.getType().equals(Wordtype.NOT)) {
            unaryop.addNode(nowWord);
        } else {
            error();
        }
        getSym();
        return unaryop;
    }

    //FuncRParams → Exp { ',' Exp }
    public Synt FuncRParams() {
        Synt funcrparams = new FuncRParams();
        Synt exp = Exp();
        funcrparams.addNode(exp);
        while (nowWord.getType().equals(Wordtype.COMMA)) {
            funcrparams.addNode(nowWord);
            getSym();
            Synt exp1 = Exp();
            funcrparams.addNode(exp1);
        }
        return funcrparams;
    }

    //MulExp → UnaryExp | MulExp ('*' | '/' | '%') UnaryExp
    public Synt MulExp() {
        Synt mulexp = new MulExp();
        Synt unaryexp = UnaryExp();
        mulexp.addNode(unaryexp);
        while (nowWord.getType().equals(Wordtype.MULT) || nowWord.getType().equals(Wordtype.DIV) ||
                nowWord.getType().equals(Wordtype.MOD)) {
            Synt mulexp1 = mulexp;
            mulexp = new MulExp();
            mulexp.addNode(mulexp1);
            mulexp.addNode(nowWord);
            getSym();
            Synt unaryexp1 = UnaryExp();
            mulexp.addNode(unaryexp1);
        }
        return mulexp;
    }

    //AddExp → MulExp | AddExp ('+' | '−') MulExp
    public Synt AddExp() {
        Synt addexp = new AddExp();
        Synt mulexp = MulExp();
        addexp.addNode(mulexp);
        while (nowWord.getType().equals(Wordtype.PLUS) || nowWord.getType().equals(Wordtype.MINU)) {
            Synt addexp1 = addexp;
            addexp = new AddExp();
            addexp.addNode(addexp1);
            addexp.addNode(nowWord);
            getSym();
            Synt mulexp1 = MulExp();
            addexp.addNode(mulexp1);
        }
        return addexp;
    }

    //RelExp → AddExp | RelExp ('<' | '>' | '<=' | '>=') AddExp
    public Synt RelExp() {
        Synt relexp = new RelExp();
        Synt addexp = AddExp();
        relexp.addNode(addexp);
        while (nowWord.getType().equals(Wordtype.LSS) || nowWord.getType().equals(Wordtype.GRE) ||
                nowWord.getType().equals(Wordtype.LEQ) || nowWord.getType().equals(Wordtype.GEQ)) {
            Synt relexp1 = relexp;
            relexp = new RelExp();
            relexp.addNode(relexp1);
            relexp.addNode(nowWord);
            getSym();
            Synt addexp1 = AddExp();
            relexp.addNode(addexp1);
        }
        return relexp;
    }

    //EqExp → RelExp | EqExp ('==' | '!=') RelExp
    public Synt EqExp() {
        Synt eqexp = new EqExp();
        Synt relexp = RelExp();
        eqexp.addNode(relexp);
        while (nowWord.getType().equals(Wordtype.EQL) || nowWord.getType().equals(Wordtype.NEQ)) {
            Synt eqexp1 = eqexp;
            eqexp = new EqExp();
            eqexp.addNode(eqexp1);
            eqexp.addNode(nowWord);
            getSym();
            Synt relexp1 = RelExp();
            eqexp.addNode(relexp1);
        }
        return eqexp;
    }

    //LAndExp → EqExp | LAndExp '&&' EqExp
    public Synt LAndExp() {
        Synt landexp = new LAndExp();
        Synt eqexp = EqExp();
        landexp.addNode(eqexp);
        while (nowWord.getType().equals(Wordtype.AND)) {
            Synt landexp1 = landexp;
            landexp = new LAndExp();
            landexp.addNode(landexp1);
            landexp.addNode(nowWord);
            getSym();
            Synt eqexp1 = EqExp();
            landexp.addNode(eqexp1);
        }
        return landexp;
    }

    //LOrExp → LAndExp | LOrExp '||' LAndExp
    public Synt LOrExp() {
        Synt lorexp = new LOrExp();
        Synt landexp = LAndExp();
        lorexp.addNode(landexp);
        while (nowWord.getType().equals(Wordtype.OR)) {
            Synt lorexp1 = lorexp;
            lorexp = new LOrExp();
            lorexp.addNode(lorexp1);
            lorexp.addNode(nowWord);
            getSym();
            Synt landexp1 = LAndExp();
            lorexp.addNode(landexp1);
        }
        return lorexp;
    }

    //ConstExp → AddExp
    public Synt ConstExp() {
        Synt constexp = new ConstExp();
        Synt addexp = AddExp();
        constexp.addNode(addexp);
        return constexp;
    }

    public void error() {
        System.out.println(nowWord.getLindex());
        System.out.println("E_R_R_O_R");
        System.out.println(pointer);
        System.out.println(nowWord);
        System.exit(0);
    }
}
